package jp.millibit.util
{
	import flash.events.EventDispatcher;
	import flash.events.TimerEvent;
	import flash.utils.Timer;

	public class GCWatcher extends EventDispatcher
	{

		private static const DELAY:int = 50;

		private static var _tail:Holder;

		private static var _numRefs:int = 0;

		private static var _pendingList:Array = [];

		private static var _initialized:Boolean = false;

		private static var _timer:Timer2;

		public function GCWatcher()
		{
			if (!_initialized)
			{
				_initialized = true;
				_timer = new Timer2(DELAY);
				_timer.addEventListener(TimerEvent.TIMER, timerHandler);

				_tail = new Holder();
			}
		}

		internal function register(ref:WeakReference):void
		{
			_pendingList.push([ref, this]);
			_timer.increment();
		}

		private static function timerHandler(e:TimerEvent):void
		{
			var holder:Holder;
			for (var i:int = 0, len:uint = _pendingList.length; i < len; i++)
			{
				var h:Array = _pendingList.shift();

				holder = new Holder();
				holder.previous = _tail;
				_tail.next = holder;
				_tail.ref = h[0];
				_tail.watcher = h[1];
				_tail = holder;
			}

			var dispatchList:Array = [];
			holder = _tail;

			while (holder = holder.previous)
			{
				var ref:WeakReference = holder.ref;
				if (ref.object === null)
				{
					var p:Holder = holder.previous;
					var n:Holder = holder.next;

					n.previous = p;
					if (p !== null)
					{
						p.next = n;
					}

					_timer.decrement();
					dispatchList.push(holder);
				}
			}

			for (i = 0, len = dispatchList.length; i < len; i++)
			{
				holder = dispatchList[i];
				holder.watcher.dispatchEvent(new GCEvent(GCEvent.GC, holder.ref));
			}
		}
	}
}

import flash.utils.Timer;
import jp.millibit.util.WeakReference;
import jp.millibit.util.GCWatcher;

class Holder
{
	public var next:Holder;

	public var previous:Holder;

	public var ref:WeakReference;

	public var watcher:GCWatcher;

	public function Holder()
	{
	}
}

class Timer2 extends Timer
{

	public var refCount:int;

	public function Timer2(delay:int)
	{
		super(delay);
		refCount = 0;
	}

	public function increment():void
	{
		if (++refCount === 1 && !running)
		{
			start();
		}
	}

	public function decrement():void
	{
		if (--refCount <= 0 && running)
		{
			stop();
		}
	}
}
